package cn.da.shuai.cool.finance.service.impl;

import cn.da.shuai.cool.finance.model.CoolGeneralLedger;
import cn.da.shuai.cool.finance.mapper.CoolGeneralLedgerMapper;
import cn.da.shuai.cool.finance.service.ICoolGeneralLedgerService;
import cn.da.shuai.cool.mybatis.service.impl.CoolServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

/**
 * <p>
 * 总账表 服务实现类
 * </p>
 *
 * @author 大帅哥
 * @since 2023-05-01
 */
@Service
public class CoolGeneralLedgerServiceImpl extends CoolServiceImpl<CoolGeneralLedgerMapper, CoolGeneralLedger> implements ICoolGeneralLedgerService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean postTransaction(CoolGeneralLedger ledger) {
        // 1. 检查会计分录是否平衡
        if (!checkAccountingBalance(ledger)) {
            throw new RuntimeException("会计分录借贷不平衡");
        }

        // 2. 检查会计期间是否关闭
        if (isPeriodClosed(ledger.getTransactionDate())) {
            throw new RuntimeException("会计期间已关闭，不能过账");
        }

        // 3. 更新科目余额
        updateAccountBalance(ledger);

        // 4. 保存会计分录
        return save(ledger);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean closePeriod(LocalDate periodEndDate) {
        // 1. 检查是否存在未过账的交易
        if (hasUnpostedTransactions(periodEndDate)) {
            throw new RuntimeException("存在未过账的交易，不能结账");
        }

        // 2. 计算本期损益
        calculatePeriodProfitAndLoss(periodEndDate);

        // 3. 结转本期损益
        transferProfitAndLoss(periodEndDate);

        // 4. 更新期间状态
        return updatePeriodStatus(periodEndDate);
    }

    @Override
    public BigDecimal getAccountBalance(String accountCode, LocalDate date) {
        LambdaQueryWrapper<CoolGeneralLedger> wrapper = new LambdaQueryWrapper<CoolGeneralLedger>()
                .eq(CoolGeneralLedger::getAccountCode, accountCode)
                .le(CoolGeneralLedger::getTransactionDate, date);

        List<CoolGeneralLedger> ledgers = list(wrapper);

        BigDecimal balance = BigDecimal.ZERO;
        for (CoolGeneralLedger ledger : ledgers) {
            balance = balance.add(ledger.getDebitAmount().subtract(ledger.getCreditAmount()));
        }

        return balance;
    }

    @Override
    public List<Map<String, Object>> getTrialBalance(LocalDate startDate, LocalDate endDate) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 1. 获取所有科目
        Set<String> accountCodes = getAllAccountCodes();

        // 2. 计算每个科目的期初余额、本期发生额、期末余额
        for (String accountCode : accountCodes) {
            Map<String, Object> accountBalance = new HashMap<>();
            accountBalance.put("accountCode", accountCode);

            // 期初余额
            BigDecimal openingBalance = getAccountBalance(accountCode, startDate.minusDays(1));
            accountBalance.put("openingBalance", openingBalance);

            // 本期发生额
            BigDecimal periodDebit = getPeriodAmount(accountCode, startDate, endDate, true);
            BigDecimal periodCredit = getPeriodAmount(accountCode, startDate, endDate, false);
            accountBalance.put("periodDebit", periodDebit);
            accountBalance.put("periodCredit", periodCredit);

            // 期末余额
            BigDecimal closingBalance = openingBalance.add(periodDebit).subtract(periodCredit);
            accountBalance.put("closingBalance", closingBalance);

            result.add(accountBalance);
        }

        return result;
    }

    @Override
    public Map<String, Object> generateFinancialReport(LocalDate reportDate, String reportType) {
        Map<String, Object> report = new HashMap<>();

        switch (reportType) {
            case "BALANCE_SHEET":
                report = generateBalanceSheet(reportDate);
                break;
            case "INCOME_STATEMENT":
                report = generateIncomeStatement(reportDate);
                break;
            case "CASH_FLOW_STATEMENT":
                report = generateCashFlowStatement(reportDate);
                break;
            default:
                throw new RuntimeException("不支持的报表类型");
        }

        return report;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reverseEntry(String originalVoucherNo) {
        // 1. 获取原始凭证
        CoolGeneralLedger originalLedger = getByVoucherNo(originalVoucherNo);
        if (originalLedger == null) {
            throw new RuntimeException("原始凭证不存在");
        }

        // 2. 创建冲销分录
        CoolGeneralLedger reversalLedger = new CoolGeneralLedger();
        reversalLedger.setAccountCode(originalLedger.getAccountCode());
        reversalLedger.setAccountName(originalLedger.getAccountName());
        reversalLedger.setDebitAmount(originalLedger.getCreditAmount());
        reversalLedger.setCreditAmount(originalLedger.getDebitAmount());
        reversalLedger.setTransactionDate(LocalDate.now());
        reversalLedger.setDescription("冲销凭证：" + originalVoucherNo);

        // 3. 过账冲销分录
        return postTransaction(reversalLedger);
    }

    @Override
    public boolean checkAccountingBalance(CoolGeneralLedger ledger) {
        return ledger.getDebitAmount().compareTo(ledger.getCreditAmount()) == 0;
    }

    // 私有辅助方法

    private boolean isPeriodClosed(LocalDate date) {
        // 实现会计期间关闭状态检查逻辑
        return false;
    }

    private void updateAccountBalance(CoolGeneralLedger ledger) {
        // 实现科目余额更新逻辑
    }

    private boolean hasUnpostedTransactions(LocalDate date) {
        // 实现未过账交易检查逻辑
        return false;
    }

    private void calculatePeriodProfitAndLoss(LocalDate date) {
        // 实现本期损益计算逻辑
    }

    private void transferProfitAndLoss(LocalDate date) {
        // 实现损益结转逻辑
    }

    private boolean updatePeriodStatus(LocalDate date) {
        // 实现期间状态更新逻辑
        return true;
    }

    private Set<String> getAllAccountCodes() {
        // 实现获取所有科目编码逻辑
        return new HashSet<>();
    }

    private BigDecimal getPeriodAmount(String accountCode, LocalDate startDate, LocalDate endDate, boolean isDebit) {
        // 实现获取期间发生额逻辑
        return BigDecimal.ZERO;
    }

    private Map<String, Object> generateBalanceSheet(LocalDate date) {
        // 实现资产负债表生成逻辑
        return new HashMap<>();
    }

    private Map<String, Object> generateIncomeStatement(LocalDate date) {
        // 实现利润表生成逻辑
        return new HashMap<>();
    }

    private Map<String, Object> generateCashFlowStatement(LocalDate date) {
        // 实现现金流量表生成逻辑
        return new HashMap<>();
    }

    private CoolGeneralLedger getByVoucherNo(String voucherNo) {
        // 实现根据凭证号获取总账记录逻辑
        return null;
    }
}